﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Eneta.Portal.Common.Dto;
using Microsoft.SharePoint;
using System.Web;

namespace Eneta.Portal.Common.Repository
{
    /// <summary>
    /// Repository for announcements.
    /// </summary>
    public class AnnouncementRepository : NewsItemRepository
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AnnouncementRepository"/> class.
        /// </summary>
        public AnnouncementRepository(SPWeb web) : base(web)
        {
       
        }

        /// <summary>
        /// Approves the announcement.
        /// </summary>
        /// <param name="id">The id of announcement to approve.</param>
        /// <param name="comment">The comment by moderator.</param>
        public void ApproveAnnouncement(int id, string comment)
        {
            var sec = new SPSecurity.CodeToRunElevated(delegate
                  {
                      using(var site = new SPSite(SiteId))
                      using(var web = site.OpenWeb())
                      {
                          SetAnnouncementStatus(web, id, SPModerationStatusType.Approved,  comment);
                      }
                  }                                         
                );
            SPSecurity.RunWithElevatedPrivileges(sec);
        }

        /// <summary>
        /// Denies the announcement.
        /// </summary>
        /// <param name="id">The id of announcement.</param>
        /// <param name="comment">The comment by moderator.</param>
        public void DenyAnnouncement(int id, string comment)
        {
            var sec = new SPSecurity.CodeToRunElevated(delegate
            {
                using (var site = new SPSite(SiteId))
                using (var web = site.OpenWeb())
                {
                    SetAnnouncementStatus(web, id, SPModerationStatusType.Denied, comment);
                }
            }
                );
            SPSecurity.RunWithElevatedPrivileges(sec);
        }

        /// <summary>
        /// Gets the announcements RSS.
        /// </summary>
        /// <returns>Returns announcements RSS as string.</returns>
        public string GetAnnouncementsRss()
        {
            var items = GetApprovedAnnouncements(1, 25);

            var title = "Eneta portaal: Teated";
            var url = "http://www.eneta.ee/uudised/teated/";

            return CreateRss(title, url, items.Results);
        }

        /// <summary>
        /// Gets announcement comments RSS as string.
        /// </summary>
        /// <returns>
        /// Returns announcement comments RSS as string.
        /// </returns>
        public new string GetCommentsRss()
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                           {
                               using(var site = new SPSite(SiteId))
                               using(var web = site.OpenWeb("/uudised/teated/"))
                               {
                                   rss = GetCommentsRss(web);
                               }

                           });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        /// <summary>
        /// Gets the comments list of comments for all announcements.
        /// </summary>
        /// <param name="limit">The number of comments to return. 0 means return all.</param>
        public IList<CommentDto> GetComments(int limit)
        {
            IList<CommentDto> result = new List<CommentDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
            {
                using (var site = new SPSite(SiteId))
                using (var web = site.OpenWeb("/uudised/teated/"))
                {
                    result = GetComments(web, limit);
                }

            });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return result;
        }

        private IList<CommentDto> GetComments(SPWeb web, int limit)
        {
            var list = web.Lists["Comments"];
            var queryString = "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
            var query = new SPQuery
            {
                Query = queryString,
                RowLimit = 50
            };

            var items = list.GetItems(query);
            var comments = CreateComments(items, true).Take(limit).ToList();

            return comments;
        }

        private string GetCommentsRss(SPWeb web)
        {
            var list = web.Lists["Comments"];
            var queryString = "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
            var query = new SPQuery
            {
                Query = queryString,
                RowLimit = 50
            };

            var items = list.GetItems(query);
            var comments = CreateComments(items, true).Take(25).ToList();

            //var items = GetApprovedAnnouncements(25);            
            var title = "Eneta portaal: Teadete kommentaarid";
            var url = "http://www.eneta.ee/uudised/teated/";

            return CreateCommentsRss(title, url, comments);
        }

        private IList<CommentDto> CreateComments(SPListItemCollection items, bool excludeUnapproved)
        {
            IList<CommentDto> comments = new List<CommentDto>();

            foreach(SPListItem item in items)
            {
                var comment = CreateComment(item);
                if(excludeUnapproved)
                    if (comment.Parent.Status != SPModerationStatusType.Approved)
                        continue;
                comments.Add(comment);
            }

            return comments;
        }

        private CommentDto CreateComment(SPListItem item)
        {
            if (item == null)
                return null;

            AnnouncementDto announcement = null;
            
            if(item["NewsPage"] != null)
            {
                var annValue = new SPFieldLookupValue(item["NewsPage"].ToString());
                announcement = GetAnnouncementById(annValue.LookupId);
            }

            var comment = CreateComment(announcement, item);
            return comment;
        }

        private string CreateRss(string title, string viewUrl, IEnumerable<AnnouncementDto> entries)
        {
            var builder = new StringBuilder(GetRssHeader(title, viewUrl));
            if (entries == null)
            {
                builder.Append(GetRssFooter());
                return builder.ToString();
            }

            foreach (var entry in entries)
            {
                if (entry == null)
                    continue;
                builder.Append("<item>");
                builder.Append("<title>");
                if (!string.IsNullOrEmpty(entry.Title))
                {
                    var utility = HttpContext.Current.Server;
                    //builder.Append(entry.Title.Replace("&", "&amp;"));
                    builder.Append(utility.HtmlEncode(entry.Title));
                }
                builder.Append("</title>\r\n");

                builder.Append("<link>");
                builder.Append("http://www.eneta.ee/uudised/teated/Lehed/" + entry.FileName);
                builder.Append("</link>\r\n");

                builder.Append("<comments>");
                builder.Append("http://www.eneta.ee/uudised/teated/Lehed/");
                builder.Append(entry.FileName);
                builder.Append("#comments</comments>\r\n");

                builder.Append("<pubDate>");
                builder.Append(entry.Created.ToString("r"));
                builder.Append("</pubDate>\r\n");

                builder.Append("<dc:creator>");
                builder.Append(entry.OwnerUserName);
                builder.Append("</dc:creator>\r\n");

                builder.Append("<guid isPermaLink=\"false\">");
                builder.Append("http://www.eneta.ee/uudised/teated/Lehed/" + entry.FileName);
                builder.Append("</guid>\r\n");

                builder.Append("<content:encoded><![CDATA[");
                builder.Append(entry.Body);
                builder.Append("]]></content:encoded>\r\n");

                //builder.Append("<wfw:commentRss>");
                //builder.Append("http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewMessages&amp;topic=");
                //builder.Append(entry.ID);
                //builder.Append("&amp;rss=1");
                //builder.Append("</wfw:commentRss>");


                builder.Append("<slash:comments>");
                builder.Append(entry.Comments.Count);
                builder.Append("</slash:comments>");

                builder.Append("</item>");
            }

            builder.Append(GetRssFooter());
            return builder.ToString();
        }

        private static void SetAnnouncementStatus(SPWeb web, int id, SPModerationStatusType status, string comment)
        {
            var list = web.Lists["Lehed"];
            var item = list.GetItemById(id);

            if (item == null)
                return;
            if (item.ModerationInformation == null)
                return;

            item.ModerationInformation.Status = status;
            item.ModerationInformation.Comment = comment;
            item.Update();
        }

        /// <summary>
        /// Gets the public announcement by id.
        /// </summary>
        /// <param name="id">The id of announcement.</param>
        public AnnouncementDto GetPublicAnnouncementById(int id)
        {
            var dto = GetAnnouncementById(id);
            if (dto.Status != SPModerationStatusType.Approved)
                return null;

            return dto;
        }

        /// <summary>
        /// Gets the announcement by id.
        /// </summary>
        /// <param name="id">The id of announcement.</param>
        public new AnnouncementDto GetAnnouncementById(int id)
        {
            AnnouncementDto dto = null;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                  {
                      using (var site = new SPSite(SiteId))
                      using (var web = site.OpenWeb("/uudised/teated/"))
                      {
                          dto = GetAnnouncementById(web, id);
                      }
                  }
                );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return dto;
        }

       private AnnouncementDto GetAnnouncementById(SPWeb web, int id)
        {
            var list = web.Lists["Lehed"];
            var item = list.GetItemById(id);
            return CreateAnnouncement(item);
        }

        /// <summary>
       /// Gets the announcements related to company with given id.
       /// </summary>
       /// <param name="companyId">The company id.</param>
       /// <param name="onlyApprovedAnnouncements">if set to <c>true</c> returns only approved announcements.</param>
        public IList<AnnouncementDto> GetAnnouncementsByCompany(int companyId, bool onlyApprovedAnnouncements)
        {
            IList<AnnouncementDto> result = null;

            var sec = new SPSecurity.CodeToRunElevated(delegate
            {
                using (var site = new SPSite(SiteId))
                using (var web = site.OpenWeb("/uudised/teated/"))
                {
                    result = GetAnnouncementsByCompany(web, companyId, onlyApprovedAnnouncements);
                }
            }
                );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return result;
        }
        private  IList<AnnouncementDto> GetAnnouncementsByCompany(SPWeb web, int companyId, bool onlyApprovedAnnouncements)
        {
            var queryString = "<Where><Eq><FieldRef Name='Companies' LookupId='True' /><Value Type='Lookup'>{0}</Value></Eq></Where>";
            queryString += "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
            queryString = string.Format(queryString, companyId);
            var list = web.Lists["Lehed"];
            var items = ExecuteQuery(list, queryString);

            var result = CreateAnnouncements(items);

            if(onlyApprovedAnnouncements)
                for(var i = result.Count-1; i >= 0; i--)
                {
                    if (result[i].Status != SPModerationStatusType.Approved)
                        result.RemoveAt(i);
                }

            return result;
        }

        /// <summary>
        /// Gets the approved announcements.
        /// </summary>
        /// <param name="limit">The number of announcements to return. 0 means return all.</param>
        /// <returns></returns>
        public PagedResult<AnnouncementDto> GetApprovedAnnouncements(int page, int pageSize)
        {
            var results = new PagedResult<AnnouncementDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
            {
                using (var site = new SPSite(SiteId))
                using (var web = site.OpenWeb("/uudised/teated/"))
                {
                    results = GetApprovedAnnouncements(web, page, pageSize);
                }
            }
                );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return results;
        }

        private PagedResult<AnnouncementDto> GetApprovedAnnouncements(SPWeb web, int page, int pageSize)
        {
            var result = new PagedResult<AnnouncementDto>();
            var list = web.Lists["Lehed"];
            var items = GetApprovedItems(list, "Uudis", "Created", false);

            if (items == null)
                return result;
            if (items.Count == 0)
                return result;

            result.Page = (page <= 0 ? 1 : page);
            result.PageSize = (pageSize <= 0 ? items.Count : pageSize);
            result.PageCount = (int)Math.Ceiling(items.Count / (decimal)result.PageSize);

            var startRow = Math.Min((result.Page - 1) * result.PageSize, items.Count);

            for (var i = startRow; i < Math.Min(startRow + result.PageSize, items.Count); i++)
            {
                var entry = CreateAnnouncement(items[i]);
                result.Results.Add(entry);
            }

            return result;
        }

        /// <summary>
        /// Gets the pending announcements.
        /// </summary>
        public IList<AnnouncementDto> GetPendingAnnouncements()
        {
            IList<AnnouncementDto> results = new List<AnnouncementDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
                  {
                      using(var site = new SPSite(SiteId))
                      using(var web = site.OpenWeb("/uudised/teated/"))
                      {
                          results = GetPendingAnnouncements(web);
                      }
                  }                                         
                );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return results;
        }

        private IList<AnnouncementDto> GetPendingAnnouncements(SPWeb web)
        {
            var list = web.Lists["Lehed"];
            var items = GetPendingItems(list, "Uudis", "Created", false);
            var results = CreateAnnouncements(items);
            return results;
        }

        private IList<AnnouncementDto> CreateAnnouncements(SPListItemCollection announcements)
        {
            IList<AnnouncementDto> results = new List<AnnouncementDto>();

            foreach (SPListItem item in announcements)
                results.Add(CreateAnnouncement(item));

            return results;
        }

        public DateTime GetLastModifiedDate()
        {
            using(var site = new SPSite(SiteId))
            using(var web = site.OpenWeb("/uudised/teated/"))
            {
                var queryString = "<OrderBy><FieldRef Name='Modified' Ascending='False' /></OrderBy>";
                var query = new SPQuery {Query = queryString, RowLimit = 1};
                var lastChange = DateTime.MinValue;

                var list = web.Lists["Lehed"];
                var items = list.GetItems(query);

                if (items != null)
                    if (items.Count > 0)
                        lastChange = (DateTime) items[0]["Modified"];

                list = web.Lists["Comments"];
                items = list.GetItems(query);

                if(items != null)
                    if (items.Count > 0)
                    {
                        var lastComment = (DateTime)items[0]["Modified"];
                        if (lastComment > lastChange)
                            lastChange = lastComment;
                    }

                return lastChange;
            }
        }
    }
}